using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Circa.Tools;
using Configuration = Circa.Configuration;

namespace Circa.Protocol.Irc {

    public class MotdEventArgs: EventArgs {

        public List<string> MotdLines { get; private set; }

        public MotdEventArgs( IEnumerable<string> motdLines ) {
            MotdLines = new List<string>( motdLines );
        }

    }

    public class Server {

        #region Public properties

        // Configuration
        public string Name { get; set; }
        public string Description { get; set; }
        public List<string> HostNames { get; set; }
        public List<ushort> Ports { get; set; }
        public string Password { get; set; }

        public Network Network { get; set; }
        public SelfUser Self { get; set; }
        public List<Channel> Channels { get; set; }

        // Runtime properties
        public bool IsRegistered { get; set; }
        public string CurrentHostName { get; set; }
        public int CurrentPort { get; set; }
        public IrcProtocolProperties ProtocolProperties { get; set; }

        public IProtocolPerformer Perform { get { return (IProtocolPerformer) protocolEngine; } }

        #endregion Public properties


        #region Private properties

        private Connection Connection { get; set; }

        #endregion Private properties


        #region Private fields

        private ProtocolEngine protocolEngine;

        #endregion Private fields


        #region Constructors

        public Server( ) {
            Channels = new List<Channel>( );
        }

        public Server( Network network, Configuration.Server conf ) {
            Name = conf.Name;
            Description = conf.Description;
            HostNames = new List<string>( conf.HostNames );
            Ports = new List<ushort>( conf.Ports );
            Password = conf.Password;

            Network = network;
            ProtocolProperties = new IrcProtocolProperties( );
        }

        #endregion Constructors


        #region Events

        public event EventHandler<EventArgs> ConnectionEstablished {
            add {
                lock ( protocolEngine ) {
                    protocolEngine.ConnectionEstablished += value;
                }
            }
            remove {
                lock ( protocolEngine ) {
                    protocolEngine.ConnectionEstablished -= value;
                }
            }
        }

        public event EventHandler<EventArgs> Registered {
            add {
                lock ( protocolEngine ) {
                    protocolEngine.Registered += value;
                }
            }
            remove {
                lock ( protocolEngine ) {
                    protocolEngine.Registered -= value;
                }
            }
        }

        #endregion


        public void Connect( ) {
            if ( null != Connection ) {
                if ( Connection.IsConnected( ) ) {
                    throw new InvalidOperationException( "Server is already connected." );
                }
                Connection.Dispose( );
                Connection = null;
            }

            if ( null == Self ) {
                throw new InvalidOperationException( "No identity configured for Server." );
            }

            Connection = ConnectionFactory.Create( this, false );
            protocolEngine = new GenericProtocolEngine { Server = this, Connection = Connection };
            Connection.Connect( );
        }

        public bool RenameTarget( string oldName, string newName ) {
            return protocolEngine.RenameTarget( oldName, newName );
        }

        //
        // Implementation
        //

        void RplISupport( IrcMessage m ) {
            Debug.Print( "Server.005" );

            ProtocolProperties.SetFromISupportTokens( m.Args );
        }

        //
        // Message Of The Day handling
        //

        public event EventHandler<MotdEventArgs> Motd;
        protected virtual void OnMotd( MotdEventArgs e ) {
            var handler = Motd;
            if ( null != handler )
                handler( this, e );
        }

        private List<string> currentMotd;

        void RplMotdStart( IrcMessage m ) {
            Debug.Print( "Server.375: args={{{0}}}", string.Join( "}{", m.Args.ToArray( ) ) );

            currentMotd = new List<string>( );
            currentMotd.Add( string.Join( " ", m.Args.ToArray( ) ) );
        }

        void RplMotd( IrcMessage m ) {
            string s = m.Args[ 0 ];
            if ( s.Substring( 0, 2 ).Equals( "- ", StringComparison.Ordinal ) ) {
                s = s.Substring( 2 );
            }
            currentMotd.Add( s );
        }

        void RplEndOfMotd( IrcMessage m ) {
            Debug.Print( "Server.376: args={{{0}}}", string.Join( "}{", m.Args.ToArray( ) ) );

            IList<string> motd = currentMotd;
            currentMotd = null;
            OnMotd( new MotdEventArgs( motd ) );
        }

        void ErrNoMotd( IrcMessage m ) {
            Debug.Print( "Server.422: args={{{0}}}", string.Join( "}{", m.Args.ToArray( ) ) );

            IList<string> motd = currentMotd;
            currentMotd = null;
            OnMotd( new MotdEventArgs( currentMotd ) );
        }

        //
        // IRC protocol verbs
        //

    }

}
